﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace SilverlightApplication.Utils
{
    public class StoryboardManager
    {
        private const string TRANSFORM_PROPERTYPATH_PART = "(FrameworkElement.RenderTransform).(TransformGroup.Children)[";
        private const string PROJECTION_PROPERTYPATH_PART = "(FrameworkElement.Projection).(PlaneProjection.";

        private Storyboard _storyboard = null;

        public Storyboard Storyboard
        {
            get { return _storyboard; }
        }

        private FrameworkElement _frameworkElement;

        public FrameworkElement FrameworkElement
        {
            get { return _frameworkElement; }
        }

        private ScaleDoubleAnimation _scaleDoubleAnimation = new ScaleDoubleAnimation();

        public ScaleDoubleAnimation ScaleDoubleAnimation
        {
            get { return _scaleDoubleAnimation; }
            set
            {
                _scaleDoubleAnimation = value;
            }
        }

        private SkewDoubleAnimation _skewDoubleAnimation = new SkewDoubleAnimation();

        public SkewDoubleAnimation SkewDoubleAnimation
        {
            get { return _skewDoubleAnimation; }
            set
            {
                _skewDoubleAnimation = value;
            }
        }

        private RotateDoubleAnimation _rotateDoubleAnimation = new RotateDoubleAnimation();

        public RotateDoubleAnimation RotateDoubleAnimation
        {
            get { return _rotateDoubleAnimation; }
            set
            {
                _rotateDoubleAnimation = value;
            }
        }

        private TranslateDoubleAnimation _translateDoubleAnimation = new TranslateDoubleAnimation();

        public TranslateDoubleAnimation TranslateDoubleAnimation
        {
            get { return _translateDoubleAnimation; }
            set
            {
                _translateDoubleAnimation = value;
            }
        }

        private ProjectionRotationDoubleAnimation _projectionRotationDoubleAnimation = new ProjectionRotationDoubleAnimation();

        public ProjectionRotationDoubleAnimation ProjectionRotationDoubleAnimation
        {
            get
            {
                return _projectionRotationDoubleAnimation;
            }
            set
            {
                if (_projectionRotationDoubleAnimation == value)
                    return;
                _projectionRotationDoubleAnimation = value;
            }
        }

        private ProjectionCenterOfRotationDoubleAnimation _projectionCenterOfRotationDoubleAnimation = new ProjectionCenterOfRotationDoubleAnimation();

        public ProjectionCenterOfRotationDoubleAnimation ProjectionCenterOfRotationDoubleAnimation
        {
            get
            {
                return _projectionCenterOfRotationDoubleAnimation;
            }
            set
            {
                if (_projectionCenterOfRotationDoubleAnimation == value)
                    return;
                _projectionCenterOfRotationDoubleAnimation = value;
            }
        }

        private ProjectionGlobalOffsetDoubleAnimation _projectionGlobalOffsetDoubleAnimation = new ProjectionGlobalOffsetDoubleAnimation();

        public ProjectionGlobalOffsetDoubleAnimation ProjectionGlobalOffsetDoubleAnimation
        {
            get
            {
                return _projectionGlobalOffsetDoubleAnimation;
            }
            set
            {
                if (_projectionGlobalOffsetDoubleAnimation == value)
                    return;
                _projectionGlobalOffsetDoubleAnimation = value;
            }
        }

        private ProjectionLocalOffsetDoubleAnimation _projectionLocalOffsetDoubleAnimation = new ProjectionLocalOffsetDoubleAnimation();

        public ProjectionLocalOffsetDoubleAnimation ProjectionLocalOffsetDoubleAnimation
        {
            get
            {
                return _projectionLocalOffsetDoubleAnimation;
            }
            set
            {
                if (_projectionLocalOffsetDoubleAnimation == value)
                    return;
                _projectionLocalOffsetDoubleAnimation = value;
            }
        }

        private OpacityDoubleAnimation _opacityDoubleAnimation = new OpacityDoubleAnimation();

        public OpacityDoubleAnimation OpacityDoubleAnimation
        {
            get
            {
                return _opacityDoubleAnimation;
            }
            set
            {
                if (_opacityDoubleAnimation == value)
                    return;
                _opacityDoubleAnimation = value;
            }
        }

        private Point _renderTransformOrigin = new Point(0.5, 0.5);

        public Point RenderTransformOrigin
        {
            get { return _renderTransformOrigin; }
            set { _renderTransformOrigin = value; }
        }


        public StoryboardManager(FrameworkElement frameworkElement)
        {
            this._frameworkElement = frameworkElement;

            FrameworkElementSet();
            _storyboard = new Storyboard();

            _scaleDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
            _skewDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
            _rotateDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
            _translateDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
            _projectionGlobalOffsetDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
            _projectionLocalOffsetDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
            _projectionCenterOfRotationDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
            _projectionRotationDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
            _opacityDoubleAnimation.DoubleAnimationChange += new DoubleAnimationChangeEventHandler(DoubleAnimation_DoubleAnimationChange);
        }

        private void DoubleAnimation_DoubleAnimationChange(object sender, DoubleAnimationChangeEventArgs e)
        {
            bool isProjection = false;
            if (((int)e.AnimationType >= (int)AnimationType.ProjectionRotation) && ((int)e.AnimationType <= (int)AnimationType.ProjectionLocalOffset))
            {
                isProjection = true;
            }
            DoubleAnimation doubleAnimation = (DoubleAnimation)sender;
            _storyboard.Children.Add(doubleAnimation);
            Storyboard.SetTarget(doubleAnimation, _frameworkElement);
            if (e.AnimationType == AnimationType.Opacity)
            {
                Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(e.Propertypath, new object[] { }));
            }
            else if (isProjection)
            {
                Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(PROJECTION_PROPERTYPATH_PART + e.Propertypath, new object[] { }));
            }
            else
            {
                Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath(TRANSFORM_PROPERTYPATH_PART + (int)e.AnimationType + e.Propertypath, new object[] { }));
            }
        }

        public void FrameworkElementSet()
        {
            _frameworkElement.RenderTransform = CreateTransformGroup();
            PlaneProjection newPlaneProjection = new PlaneProjection();
            newPlaneProjection.CenterOfRotationX = newPlaneProjection.CenterOfRotationY = newPlaneProjection.CenterOfRotationZ = 0.5;
            _frameworkElement.Projection = newPlaneProjection;
            _frameworkElement.RenderTransformOrigin = _renderTransformOrigin;
        }

        private TransformGroup CreateTransformGroup()
        {
            TransformGroup transformGroup = new TransformGroup();

            ScaleTransform scaleTransform = new ScaleTransform();
            SkewTransform skewTransform = new SkewTransform();
            RotateTransform rotateTransform = new RotateTransform();
            TranslateTransform translateTransform = new TranslateTransform();

            transformGroup.Children.Add(scaleTransform);
            transformGroup.Children.Add(skewTransform);
            transformGroup.Children.Add(rotateTransform);
            transformGroup.Children.Add(translateTransform);

            return transformGroup;
        }
    }


    public delegate void DoubleAnimationChangeEventHandler(object sender, DoubleAnimationChangeEventArgs e);

    public class DoubleAnimationChangeEventArgs : EventArgs
    {
        public AnimationType AnimationType { set; get; }
        public DoubleAnimation Value { set; get; }
        public string Propertypath { set; get; }
    }

    public class ScaleDoubleAnimation
    {
        private DoubleAnimation _scaleX;

        public DoubleAnimation ScaleX
        {
            get { return _scaleX; }
            set
            {
                _scaleX = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.ScaleX, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.Scale,
                        Value = value,
                        Propertypath = "].(ScaleTransform.ScaleX)"
                    });
            }
        }

        private DoubleAnimation _scaleY;

        public DoubleAnimation ScaleY
        {
            get { return _scaleY; }
            set
            {
                _scaleY = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.ScaleY, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.Scale,
                        Value = value,
                        Propertypath = "].(ScaleTransform.ScaleY)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public class SkewDoubleAnimation
    {
        private DoubleAnimation _angleX;

        public DoubleAnimation AngleX
        {
            get { return _angleX; }
            set
            {
                _angleX = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.AngleX, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.Skew,
                        Value = value,
                        Propertypath = "].(SkewTransform.AngleX)"
                    });
            }
        }

        private DoubleAnimation _angleY;

        public DoubleAnimation AngleY
        {
            get { return _angleY; }
            set
            {
                _angleY = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.AngleY, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.Skew,
                        Value = value,
                        Propertypath = "].(SkewTransform.AngleY)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public class RotateDoubleAnimation
    {
        private DoubleAnimation _angle;

        public DoubleAnimation Angle
        {
            get { return _angle; }
            set
            {
                _angle = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.Angle, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.Rotate,
                        Value = value,
                        Propertypath = "].(RotateTransform.Angle)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public class TranslateDoubleAnimation
    {
        private DoubleAnimation _x;

        public DoubleAnimation X
        {
            get { return _x; }
            set
            {
                _x = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.X, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.Translate,
                        Value = value,
                        Propertypath = "].(TranslateTransform.X)"
                    });
            }
        }

        private DoubleAnimation _y;

        public DoubleAnimation Y
        {
            get { return _y; }
            set
            {
                _y = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.Y, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.Translate,
                        Value = value,
                        Propertypath = "].(TranslateTransform.Y)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public class ProjectionRotationDoubleAnimation
    {
        private DoubleAnimation _rotationX;

        public DoubleAnimation RotationX
        {
            get { return _rotationX; }
            set
            {
                _rotationX = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.RotationX, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionRotation,
                        Value = value,
                        Propertypath = "RotationX)"
                    });
            }
        }

        private DoubleAnimation _rotationY;

        public DoubleAnimation RotationY
        {
            get { return _rotationY; }
            set
            {
                _rotationY = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.RotationY, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionRotation,
                        Value = value,
                        Propertypath = "RotationY)"
                    });
            }
        }

        private DoubleAnimation _rotationZ;

        public DoubleAnimation RotationZ
        {
            get { return _rotationZ; }
            set
            {
                _rotationZ = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.RotationZ, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionRotation,
                        Value = value,
                        Propertypath = "RotationZ)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public class ProjectionCenterOfRotationDoubleAnimation
    {
        private DoubleAnimation _centerOfRotationX;

        public DoubleAnimation CenterOfRotationX
        {
            get { return _centerOfRotationX; }
            set
            {
                _centerOfRotationX = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.CenterOfRotationX, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionCenterOfRotation,
                        Value = value,
                        Propertypath = "CenterOfRotationX)"
                    });
            }
        }

        private DoubleAnimation _centerOfRotationY;

        public DoubleAnimation CenterOfRotationY
        {
            get { return _centerOfRotationY; }
            set
            {
                _centerOfRotationY = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.CenterOfRotationY, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionCenterOfRotation,
                        Value = value,
                        Propertypath = "CenterOfRotationY)"
                    });
            }
        }

        private DoubleAnimation _centerOfRotationZ;

        public DoubleAnimation CenterOfRotationZ
        {
            get { return _centerOfRotationZ; }
            set
            {
                _centerOfRotationZ = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.CenterOfRotationZ, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionCenterOfRotation,
                        Value = value,
                        Propertypath = "CenterOfRotationZ)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public class ProjectionGlobalOffsetDoubleAnimation
    {
        private DoubleAnimation _globalOffsetX;

        public DoubleAnimation GlobalOffsetX
        {
            get { return _globalOffsetX; }
            set
            {
                _globalOffsetX = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.GlobalOffsetX, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionGlobalOffset,
                        Value = value,
                        Propertypath = "GlobalOffsetX)"
                    });
            }
        }

        private DoubleAnimation _globalOffsetY;

        public DoubleAnimation GlobalOffsetY
        {
            get { return _globalOffsetY; }
            set
            {
                _globalOffsetY = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.GlobalOffsetY, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionGlobalOffset,
                        Value = value,
                        Propertypath = "GlobalOffsetY)"
                    });
            }
        }

        private DoubleAnimation _globalOffsetZ;

        public DoubleAnimation GlobalOffsetZ
        {
            get { return _globalOffsetZ; }
            set
            {
                _globalOffsetZ = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.GlobalOffsetZ, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionGlobalOffset,
                        Value = value,
                        Propertypath = "GlobalOffsetZ)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public class ProjectionLocalOffsetDoubleAnimation
    {
        private DoubleAnimation _localOffsetX;

        public DoubleAnimation LocalOffsetX
        {
            get { return _localOffsetX; }
            set
            {
                _localOffsetX = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.LocalOffsetX, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionLocalOffset,
                        Value = value,
                        Propertypath = "LocalOffsetX)"
                    });
            }
        }

        private DoubleAnimation _localOffsetY;

        public DoubleAnimation LocalOffsetY
        {
            get { return _localOffsetY; }
            set
            {
                _localOffsetY = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.LocalOffsetY, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionLocalOffset,
                        Value = value,
                        Propertypath = "LocalOffsetY)"
                    });
            }
        }

        private DoubleAnimation _localOffsetZ;

        public DoubleAnimation LocalOffsetZ
        {
            get { return _localOffsetZ; }
            set
            {
                _localOffsetZ = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.LocalOffsetZ, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionLocalOffset,
                        Value = value,
                        Propertypath = "LocalOffsetZ)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public class OpacityDoubleAnimation
    {
        private DoubleAnimation _opacity;

        public DoubleAnimation Opacity
        {
            get { return _opacity; }
            set
            {
                _opacity = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.Opacity, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.Opacity,
                        Value = value,
                        Propertypath = "(Opacity)"
                    });
            }
        }

        private DoubleAnimation _localOffsetY;

        public DoubleAnimation LocalOffsetY
        {
            get { return _localOffsetY; }
            set
            {
                _localOffsetY = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.LocalOffsetY, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionLocalOffset,
                        Value = value,
                        Propertypath = "LocalOffsetY)"
                    });
            }
        }

        private DoubleAnimation _localOffsetZ;

        public DoubleAnimation LocalOffsetZ
        {
            get { return _localOffsetZ; }
            set
            {
                _localOffsetZ = value;
                if (DoubleAnimationChange != null)
                    DoubleAnimationChange(this.LocalOffsetZ, new DoubleAnimationChangeEventArgs()
                    {
                        AnimationType = AnimationType.ProjectionLocalOffset,
                        Value = value,
                        Propertypath = "LocalOffsetZ)"
                    });
            }
        }

        public event DoubleAnimationChangeEventHandler DoubleAnimationChange;
    }

    public enum AnimationType
    {
        Scale,
        Skew,
        Rotate,
        Translate,
        ProjectionRotation,
        ProjectionCenterOfRotation,
        ProjectionGlobalOffset,
        ProjectionLocalOffset,
        Opacity
    }
}
